package org.dromara.common.encrypt.utils;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.springframework.util.StringUtils;

import java.security.KeyPair;



public class SM2Util {

    public static String privateKey="308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104205126db8bb60e851428ebb6223eca75504949a5bcc5bb4b929689e0ba46875414a00a06082a811ccf5501822da144034200041b665acca408d4e827a86ad68de8cde4a1e9a36d2c58a1d85e51c2621a211c29cc64f6fe12781e2836b7a9776fdb46f9b337a6b3f46fc1aed8c1f2193a6f8376";
    public static String publicKey="3059301306072a8648ce3d020106082a811ccf5501822d034200041b665acca408d4e827a86ad68de8cde4a1e9a36d2c58a1d85e51c2621a211c29cc64f6fe12781e2836b7a9776fdb46f9b337a6b3f46fc1aed8c1f2193a6f8376";

    public static KeyPair generateKeyPair() {
        return SecureUtil.generateKeyPair("SM2");
    }


    /**
     * 解密
     * @param str 加密之后的字符串
     * @param privateKey 私钥
     * @param publicKey 公钥
     * @return 原文密码
     */
    public static String decrypt(String str, String privateKey, String publicKey) {
        try {
            if (checkKeyIsEmpty(privateKey, publicKey)) {
                SM2 sm2 = new SM2(privateKey, publicKey);
                sm2.setMode(SM2Engine.Mode.C1C3C2);
                return sm2.decryptStr(str, KeyType.PrivateKey);
            }
            return str;
        } catch (Exception e) {
            throw new RuntimeException("sm2解密失败" + e);
        }
    }

    private static boolean checkKeyIsEmpty(String privateKey, String publicKey) {
        if (StringUtils.isEmpty(privateKey) || StringUtils.isEmpty(publicKey)) {
            return false;
        }
        return true;
    }

    /**
     * 加密
     * @param str
     * @return
     */
    public static String encrypt(String str, String privateKey, String publicKey) {
        try {
            if (checkKeyIsEmpty(privateKey, publicKey)) {
                SM2 sm2 = new SM2(privateKey, publicKey);
                sm2.setMode(SM2Engine.Mode.C1C3C2);
                return sm2.encryptHex(str, KeyType.PublicKey);
            }
            return str;
        } catch (Exception e) {
            throw new RuntimeException("sm2加密失败" + e);
        }
    }
    public static void main(String[] args) {
        /**
         * privateKey=>308193020100301306072a8648ce3d020106082a811ccf5501822d0479307702010104205126db8bb60e851428ebb6223eca75504949a5bcc5bb4b929689e0ba46875414a00a06082a811ccf5501822da144034200041b665acca408d4e827a86ad68de8cde4a1e9a36d2c58a1d85e51c2621a211c29cc64f6fe12781e2836b7a9776fdb46f9b337a6b3f46fc1aed8c1f2193a6f8376
         * publicKey=>3059301306072a8648ce3d020106082a811ccf5501822d034200041b665acca408d4e827a86ad68de8cde4a1e9a36d2c58a1d85e51c2621a211c29cc64f6fe12781e2836b7a9776fdb46f9b337a6b3f46fc1aed8c1f2193a6f8376
         * 公钥Q:041b665acca408d4e827a86ad68de8cde4a1e9a36d2c58a1d85e51c2621a211c29cc64f6fe12781e2836b7a9776fdb46f9b337a6b3f46fc1aed8c1f2193a6f8376
         * 私钥D:5126db8bb60e851428ebb6223eca75504949a5bcc5bb4b929689e0ba46875414
         */
        String text = "我是一段测试aaaa";
        // 生成密钥对
        KeyPair keyPair = SM2Util.generateKeyPair();
        // 服务器端使用
        // 生成私钥
        String privateKey = HexUtil.encodeHexStr(keyPair.getPrivate().getEncoded());
        // 生成公钥
        String publicKey = HexUtil.encodeHexStr(keyPair.getPublic().getEncoded());
        System.out.println("privateKey=>" + privateKey);
        System.out.println("publicKey=>" + publicKey);

        // 前端使用
        // 生成公钥 Q，以Q值做为js端的加密公钥
        String publicKeyQ = HexUtil.encodeHexStr(((BCECPublicKey) keyPair.getPublic()).getQ().getEncoded(false));
        System.out.println("公钥Q:"+ publicKeyQ);
        // 生成私钥 D，以D值做为js端的解密私钥
        String privateKeyD = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(keyPair.getPrivate()));
        System.out.println("私钥D:"+ privateKeyD);

        // 服务端加解密
        String encodeStr = SM2Util.encrypt(text, privateKey, publicKey);
        String formatStr = SM2Util.decrypt(encodeStr, privateKey, publicKey);
        System.out.println("encodeStr=>" + encodeStr);
        System.out.println("formatStr=>" + formatStr);
    }
}
